%%

%{
  private int comment_count = 0;
%} 

%line
%char
%unicode
%state ESTADO_STRING
%state ESTADO_COMENTARIO
%state ESTADO_COMENTARIO2
//%full

//%debug
%class Scanner

%{
	StringBuffer string = new StringBuffer();
	
	private void escribirTraza(String tipoToken,int linea,String contenido){
		System.out.println("Token: \""+contenido+"\"    "+tipoToken+" Linea: "+ linea);
	}
	
	private Yytoken generaToken(String tipoToken,Object contenido ,int linea){
		Object atributos;
		if(tipoToken.equals("PUNT") || tipoToken.equals("OP_COMP") || tipoToken.equals("OP_MAT") || tipoToken.equals("OP_LOG") ||tipoToken.equals("STRING")){
			atributos=(String)contenido;
		}
		else{
			if(tipoToken.equals("IDENTIFICADOR" )){
                                   atributos = tablaSimbolos.obtenerPalRes((String)contenido);
                                   if(atributos == null){
                                    atributos=tablaSimbolos.insertaTabla((String)contenido);
						escribirTraza("IDENTIFICADOR",yyline+1,yytext()); 
                                   }
                                   else{tipoToken = "PAL_RES";escribirTraza("PAL_RES",yyline+1,yytext()); }
				}
				else{
					if(tipoToken.equals("INTEGER")){
						atributos=(Integer)contenido;
					}
					else{
						if(tipoToken.equals("REAL" )){
							atributos=(Float)contenido;
						}
						else{
							if(tipoToken.equals("CHAR" )){
								atributos=(Character)contenido;
							}
							else{
								//si es abre/cierra parentesis, asignacion,op_punt, corchetes, no tiene atrib 
								atributos=null;
							}
						}
					}
			//	}
			}
		}
		return (new Yytoken(tipoToken,atributos,linea));
	}
%}

LETRA=[A-Za-z]
DIGITO=[0-9]
IDENTIFICADOR={LETRA}({LETRA}|{DIGITO}|_)*
ESPACIO=\r|\n|\r\n|\t|[\ ]*
ENTERO={DIGITO}+
REAL={ENTERO}("."{ENTERO})(("e"|"E")("+"|"-")?{ENTERO})?
PUNT=","|":"|";"|"."
OP_COMP=">"|"<"|"="
OP_MAT="+"|"-"|"*"|"/"
OP_LOG="and"|"or"|"xor"|"not"|"AND"|"OR"|"NOT"|"XOR"|"shl"|"SHL"|"shr"|"SHR"
LETRAHEX=[A-F]
HEXADECIMAL="$"({LETRAHEX}|{DIGITO})*

//ERRORES
ERROR1={ENTERO}({IDENTIFICADOR})|({REAL})({IDENTIFICADOR}})|({ENTERO})({LETRA}})|({REAL})({LETRA}) //identificador mal formado
//operador mal formado-> lo quitamos porque no tiene mucho sentido.
ERROR2="'"{IDENTIFICADOR}"'"|"'"{ENTERO}"'"|"'"{REAL}"'"|"'"{OP_LOG}"'" |"'"PAL_RES"'"//caracter mal formado
//el error 3 es el de caracter ilegal
ERROR4={ENTERO}(".")(("e"|"E")("+"|"-")?{ENTERO})|{ENTERO}("."{ENTERO})(("e"|"E")("+"|"-")?)?//real mal formado
%% 
<YYINITIAL> {
  "^"  { 	escribirTraza("OP_PUNT",yyline+1,yytext());
		return generaToken ("OP_PUNT",null,yyline+1); }
  "<>" { 	escribirTraza("OP_COMP",yyline+1,yytext());
		return generaToken("OP_COMP",new String(yytext()), yyline+1);}
  "<=" { 	escribirTraza("OP_COMP",yyline+1,yytext());
		return generaToken("OP_COMP",new String(yytext()), yyline+1);}
  ">=" { 	escribirTraza("OP_COMP",yyline+1,yytext());
		return generaToken("OP_COMP",new String(yytext()), yyline+1);}
  ":=" { 	escribirTraza("OP_ASIG",yyline+1,yytext());
		return (generaToken("OP_ASIG",null,yyline+1)); }
  "["	 { 	escribirTraza("ABRE_CORCHETE",yyline+1,yytext());
		return (generaToken("ABRE_CORCHETE",null,yyline+1)); }
  "]"  { 	escribirTraza("CIERRA_CORCHETE",yyline+1,yytext());
		return (generaToken("CIERRA_CORCHETE",null,yyline+1)); }
  "(." { 	escribirTraza("ABRE_CORCHETE",yyline+1,yytext());
		return (generaToken("ABRE_CORCHETE",null,yyline+1)); }
  ".)" { 	escribirTraza("CIERRA_CORCHETE",yyline+1,yytext());
		return (generaToken("CIERRA_CORCHETE",null,yyline+1)); }
  "("  {	escribirTraza("ABRE_PAREN",yyline+1,yytext());
		return (generaToken("ABRE_PAREN",null,yyline+1)); }
  ")"  {	escribirTraza("CIERRA_PAREN",yyline+1,yytext());
		return (generaToken("CIERRA_PAREN",null,yyline+1)); }
  "(*" { 	yybegin(ESTADO_COMENTARIO2);}     /*llave*/
  "{"  { 	yybegin(ESTADO_COMENTARIO);}
  \"   {	string.setLength(0); yybegin(ESTADO_STRING);}
  }
<ESTADO_STRING> {
  \"   		{yybegin(YYINITIAL);
	  	 	 System.out.println("He encontrado un String " + string.toString());
			 return generaToken("STRING",string.toString(),yyline+1); }
[^\"\\]+ 	      { string.append( yytext() ); }
}
<ESTADO_COMENTARIO> {
 "}"  		{yybegin(YYINITIAL);}
 [^"}"]+     	{ }
}
<ESTADO_COMENTARIO2> {
 "*)"			{yybegin(YYINITIAL);}
 "*"			{ }
 ")"			{ }
 [^"*)"]+     	{ }
}

<<EOF>> {
	System.out.println("Fin fichero");
	return (new Yytoken("EOF",yytext(),yyline+1));
}
{OP_MAT} {
	escribirTraza("OP_MAT",yyline+1,yytext());
	yybegin(YYINITIAL);
	return generaToken("OP_MAT",new String(yytext()), yyline+1);
}
{OP_COMP} {
	escribirTraza("OP_COMP",yyline+1,yytext());
	yybegin(YYINITIAL);
	return generaToken("OP_COMP",new String(yytext()), yyline+1);
}
{PUNT} {
	escribirTraza("PUNT",yyline+1,yytext());
	yybegin(YYINITIAL);
	return generaToken("PUNT",new String(yytext()), yyline+1);

}
{OP_LOG} {
	escribirTraza("OP_LOG",yyline+1,yytext());	
	yybegin(YYINITIAL);
	return generaToken("OP_LOG",new String(yytext()), yyline+1);
}

{IDENTIFICADOR} {
	yybegin(YYINITIAL);
	return generaToken("IDENTIFICADOR",new String(yytext()), yyline+1);
}

{ESPACIO} {
	yybegin(YYINITIAL); 
}
{ENTERO} {
	escribirTraza("ENTERO",yyline+1,yytext());
	yybegin(YYINITIAL);
	Integer aux= new Integer(Integer.valueOf(yytext()));
	return generaToken("INTEGER",aux,yyline+1); 
}
{REAL} {
	escribirTraza("REAL",yyline+1,yytext());
	yybegin(YYINITIAL);
	Float aux1=new Float(Float.valueOf(yytext()));
	return generaToken("REAL",aux1,yyline+1); 
}
"#"{ENTERO} {
	yybegin(YYINITIAL);
	String k=yytext();
	k=k.substring(1);//quitamos el primer elemento(#)
	Integer aux=Integer.parseInt(k);
      char c= (char )aux.intValue();
	//k=k.valueOf(c);
	Character aux2 = new Character(c);
	if(aux.intValue()>127){
            System.out.println("caracter mal formado: valor superior a 127");
            throw new ExcepcionLexico(yyline+1,2);//error de caracter mal formado.
        }
      else{
		escribirTraza("CHAR",yyline+1,yytext());
		return generaToken("CHAR",aux2,yyline+1);
	}
}
"'"[^\n\r\t]"'" {
	escribirTraza("CHAR",yyline+1,yytext());
	yybegin(YYINITIAL);
	return generaToken("CHAR",new Character(yytext().charAt(1)),yyline+1); 
}
{HEXADECIMAL} {
	escribirTraza("ENTERO",yyline+1,yytext());


	/*realizar la conversion del texto a hexadecimal*/
            String auxiliar=yytext();
            auxiliar=auxiliar.substring(1);//quitamos el "$"
            int traduccionHex=0;
            int numBase=1;//iremos guardando aqui las potencias de 16
            char c;int j;
            for(int i=0;i<auxiliar.length();i++){
                c=auxiliar.charAt(auxiliar.length()-i-1);
                j =Character.digit(c,16);
                traduccionHex+=j*numBase;
                numBase=numBase*16;
            }
        System.out.println("Valor: "+traduccionHex);
	return generaToken("INTEGER",new Integer(traduccionHex),yyline+1);
	}
{ERROR1} {
	System.out.println("Error encontrado: identificador mal formado");
	yybegin(YYINITIAL);
	throw new ExcepcionLexico(yyline+1,1);
}
{ERROR2} {
	System.out.println("Error encontrado: Caracter mal formado");
	yybegin(YYINITIAL);
	throw new ExcepcionLexico(yyline+1,2);
}
{ERROR4} {
	System.out.println("Error encontrado: Real mal formado");
	yybegin(YYINITIAL);
	throw new ExcepcionLexico(yyline+1,4);
}

. {
  	System.out.println("Error encontrado: no se esperaba el caracter");
	yybegin(YYINITIAL);
	throw new ExcepcionLexico(yyline+1,3);
}